import {
    Accessor,
    Component,
    For,
    Match,
    Show,
    Switch,
    useContext,
} from "solid-js";
import { getIconForFile, getIconForFolder } from "monaco-editor-solid";
import { IconWrapper } from "monaco-editor-solid";
import type FS from "@isomorphic-git/lightning-fs";
import { CodingSystemContext } from "../CodingApp";
import { Atom, atom, createIgnoreFirst, resource } from "@cn-ui/use";

/* 文件浏览器组件 */
export const FileExplorer = () => {
    const { fs, explorerVisible, editorOpenFile, storeReady } =
        useContext(CodingSystemContext);
    const initPath = "/";

    const { jumpTo, back, enter, fileList, path } = createControl(
        fs,
        editorOpenFile
    );
    createIgnoreFirst(() => {
        console.log("完成初次加载");
        fileList.refetch();
    }, [storeReady.isReady]);
    const nameEntering = atom<"file" | "folder">(null);
    const newName = atom("");
    jumpTo(initPath);
    return (
        <nav
            class="select-none h-full text-sm  flex flex-col bg-neutral-50 min-w-[8rem]"
            classList={{
                hidden: !explorerVisible(),
            }}
        >
            <header class="flex items-center gap-1">
                <div
                    class="flex-1 m-2 outline-none"
                    onclick={() => {
                        let _path = prompt("请输入路径");
                        _path && path(_path);
                    }}
                >
                    {path()}
                </div>

                <IconWrapper name="chevron-left" onclick={back}></IconWrapper>

                <IconWrapper
                    name="file-add"
                    onclick={() => nameEntering("file")}
                ></IconWrapper>
                <IconWrapper
                    name="new-folder"
                    onclick={() => nameEntering("folder")}
                ></IconWrapper>
            </header>
            <div class="flex flex-col overflow-auto overflow-x-hidden h-full">
                <Show when={nameEntering()}>
                    {
                        <span class="flex items-center justify-between  w-full cursor-pointer  transition-colors py-2">
                            <Switch>
                                <Match when={nameEntering() === "file"}>
                                    <IconWrapper name="file-add"></IconWrapper>
                                </Match>
                                <Match when={nameEntering() === "folder"}>
                                    <IconWrapper name="new-folder"></IconWrapper>
                                </Match>
                            </Switch>
                            <input
                                class="outline-none flex-shrink w-16 rounded-md "
                                type="text"
                                value={newName()}
                                oninput={(e) =>
                                    newName((e.target as any).value)
                                }
                            />
                            <IconWrapper
                                name="check"
                                onclick={() => {
                                    const newPath = path() + newName();
                                    switch (nameEntering()) {
                                        case "file":
                                            fs.promises.writeFile(newPath, "");
                                            editorOpenFile()(newPath);
                                            break;
                                        case "folder":
                                            fs.promises.mkdir(newPath);
                                            break;
                                    }
                                    nameEntering(null);
                                    newName("");
                                    fileList.refetch();
                                }}
                            ></IconWrapper>
                        </span>
                    }
                </Show>
                <For each={fileList()}>
                    {(item) => {
                        const name = item.name;
                        return (
                            <FileTab
                                name={name}
                                isFile={item.isFile()}
                                onclick={() => {
                                    enter(name, item.isFile());
                                    // props.setState("code");
                                }}
                            ></FileTab>
                        );
                    }}
                </For>
            </div>
        </nav>
    );
};

/* 单个的文件的选项卡 */
export const FileTab: Component<{
    name: string;
    isFile: boolean;
    onclick: Function;
}> = (props) => {
    const src =
        "https://cdn.jsdelivr.net/gh/vscode-icons/vscode-icons/icons/" +
        (props.isFile
            ? getIconForFile(props.name)
            : getIconForFolder(props.name));
    return (
        <span
            class="flex items-center w-full cursor-pointer hover:bg-gray-200 transition-colors"
            onclick={props.onclick as any}
        >
            <img class="w-4 h-4 mx-2" src={src} alt="" />
            {props.name}
        </span>
    );
};

/* 创建文件浏览器的控制器 */
function createControl(fs: FS, openFile: Atom<(code: string) => void>) {
    const path = atom("/");
    /* 获取文件列表，其中的元素为 Stats 并扩充 name 属性 */
    const getFileList = async (path: string) => {
        const list: string[] = await fs.promises.readdir(path);
        return Promise.all(
            list.map((name) =>
                fs.promises.stat(path + "/" + name).then((res) => {
                    return Object.assign(res, { name }) as FS.Stats & {
                        name: string;
                    };
                })
            )
        );
    };
    const fileList = resource(() => {
        return getFileList(path());
    });
    // 必定是文件夹
    const jumpTo = async (newPath: string) => {
        path(newPath);
        return fileList.refetch();
    };
    const enter = async (subPath: string, isFile: boolean) => {
        if (isFile) {
            const newPath = `${path()}${subPath}`;

            return openFile()(newPath);
        }
        const newPath = `${path()}${subPath}/`;
        return jumpTo(newPath);
    };
    const back = () => {
        const newPath = path().replace(/[^\/]+\/$/, "");
        if (newPath !== path()) {
            return jumpTo(newPath);
        }
        return;
    };
    return { jumpTo, back, enter, fileList, path };
}
